package sf.database.template.mybatis;

import org.apache.ibatis.session.Configuration;
import sf.database.jdbc.sql.SQLContext;
import sf.database.jdbc.sql.SQLParameter;
import sf.database.template.TemplateRender;
import sf.database.template.sql.SqlHelp;
import sf.spring.util.CollectionUtils;
import sf.tools.StringUtils;
import sf.tools.codec.HashUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MybatisHelp {
    private Map<String, String> templateMap = new HashMap<>();

    Configuration configuration = new Configuration();

    private static MybatisHelp instance = null;

    public static MybatisHelp getInstance() {
        if (instance == null) {
            instance = new MybatisHelp();
        }
        return instance;
    }

    private MybatisHelp() {

    }

    public Configuration getConfiguration() {
        return configuration;
    }

    public void putTemplate(String key, String templateContent) {
        templateContent = SqlHelp.replaceLineSql(templateContent);
        templateMap.put(key.trim(), templateContent.trim());
    }

    public void putAllTemplate(Map<String, String> map) {
        for (Map.Entry<String, String> entry : map.entrySet()) {
            putTemplate(entry.getKey(), entry.getValue());
        }
    }

    public String getTemplate(String key) {
        return templateMap.get(key);
    }

    public String getTemplate(String key, String dbType) {
        String template = templateMap.get(TemplateRender.wrapKey(key, dbType));
        if (template == null) {
            template = templateMap.get(key);
        }
        return template;
    }

    public String render(String key, String dbType, Map<String, Object> params, List<Object> paraList) {
        String template = getTemplate(key, dbType);
        SqlParam param = MybatisTemplate.generate(configuration, template, params);
        String sql = param.getSql();
        if (param.getParams() != null) {
            paraList.addAll(param.getParams());
        }
        return sql;
    }


    public String renderContent(String content, Map<String, Object> params, List<Object> paraList) {
        String key = HashUtils.md5(content);
        if (templateMap.get(key) == null) {
            templateMap.put(key, content);
        }
        return render(key, null, params, paraList);
    }

    public SQLContext getSqlParaPage(String key, String dbType, Map<String, Object> data) {
        String template = getTemplate(key, dbType);
        return getSqlParaPageTemplate(template, data);
    }

    public SQLContext getSqlParaPageSource(String source, Map<String, Object> data) {
        try {
            String key = HashUtils.md5(source);
            templateMap.putIfAbsent(key, source);
            String template = templateMap.get(key);
            return getSqlParaPageTemplate(template, data);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected SQLContext getSqlParaPageTemplate(String template, Map<String, Object> data) {
        if (template == null) {
            return null;
        }
        SQLContext context = new SQLContext();
        SqlParam param = MybatisTemplate.generate(configuration, template, data);
        String sql = param.getSql();
        if (CollectionUtils.isNotEmpty(param.getParams())) {
            List<SQLParameter> list = new ArrayList<>();
            for (Object o : param.getParams()) {
                SQLParameter p = new SQLParameter();
                p.setValue(o);
                list.add(p);
            }
            context.setParas(list);
        }
        String listSql = StringUtils.replaceEach(sql, new String[]{"[@page ", "[@pageIgnore ", "]"}, new String[]{" ", " ", ""});
        context.setListSql(listSql);
        StringBuilder countSql = new StringBuilder();
        int a = sql.indexOf("[@page");
        int b = sql.indexOf(']', a);
        int c = sql.indexOf("[@pageIgnore");
        int d = sql.indexOf(']', c);
        if (a > -1 && b > -1) {
            countSql.append(sql, 0, a);
            countSql.append(" count(*) ");
            if (c > -1 && d > -1) {
                countSql.append(sql, b + 1, c);
                countSql.append(sql.substring(d + 1));
            } else {
                countSql.append(sql.substring(b + 1));
            }
        }
        context.setCountSql(countSql.toString());
        return context;
    }

//    protected SQLContext getSqlParaPageTemplate2(String template, Map<String, Object> data) {
//        if (template == null) {
//            return null;
//        }
//        SQLContext context = new SQLContext();
//        try {
//            SqlParam param = MybatisTemplate.generate(configuration, template, data);
//            String sql = param.getSql();
//            if (CollectionUtils.isNotEmpty(param.getParams())) {
//                List<SQLParameter> list = new ArrayList<>();
//                for (Object o : param.getParams()) {
//                    SQLParameter p = new SQLParameter();
//                    p.setValue(o);
//                    list.add(p);
//                }
//                context.setParas(list);
//            }
//            context.setListSql(sql);
//            data.put(TemplateConstants.SQL_COUNT_KEY, true);
//            param = MybatisTemplate.generate(configuration, template, data);
//            String countSql = param.getSql();
//            context.setCountSql(countSql);
//            data.remove(TemplateConstants.SQL_COUNT_KEY);// 避免污染传入的 Map
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }
//        return context;
//    }

}
